Ce tutorial reprend le menu console créé dans le codelab preoo-01-menu (étape 4 avec navigation au clavier) et le transforme en une classe instanciable.
Dans le codelab précédent, nous avions structuré le code avec des fonctions préfixées Menu_ et des variables globales. Ce code fonctionne, mais il a une limitation : on ne peut avoir qu'un seul menu à la fois.
À travers 4 étapes progressives, vous apprendrez à :
Menu avec un constructeurProgram.csVoici le code que nous avions à la fin du codelab précédent (étape 4 — navigation au clavier) :
// Variables globales
string[] options = Array.Empty<string>();
int selectedIndex = 0;
// Programme principal
Menu_Init();
int choice = Menu_RunInteractive();
Menu_HandleChoice(choice);
Console.ReadKey();
// ============ FONCTIONS MENU ============
void Menu_Init()
{
options = new string[] { "Play", "Options", "Highscores", "Quit" };
selectedIndex = 0;
}
void Menu_ShowInteractive()
{
Console.Clear();
Console.WriteLine("=== SUPER GAME ===");
Console.WriteLine("");
Console.WriteLine("Use arrows to navigate, Enter to select");
Console.WriteLine("");
for (int i = 0; i < options.Length; i++)
{
if (i == selectedIndex)
{
Console.BackgroundColor = ConsoleColor.White;
Console.ForegroundColor = ConsoleColor.Black;
Console.WriteLine($" > {options[i]} < ");
Console.ResetColor();
}
else
{
Console.WriteLine($" {options[i]} ");
}
}
Console.WriteLine("");
}
int Menu_RunInteractive()
{
ConsoleKey key;
do
{
Menu_ShowInteractive();
ConsoleKeyInfo keyInfo = Console.ReadKey(true);
key = keyInfo.Key;
if (key == ConsoleKey.UpArrow)
{
selectedIndex--;
if (selectedIndex < 0)
{
selectedIndex = options.Length - 1;
}
}
else if (key == ConsoleKey.DownArrow)
{
selectedIndex++;
if (selectedIndex >= options.Length)
{
selectedIndex = 0;
}
}
} while (key != ConsoleKey.Enter);
return selectedIndex;
}
void Menu_HandleChoice(int choice)
{
Console.Clear();
Console.WriteLine($">>> {options[choice].ToUpper()} <<<");
}
| Champ de la classe | Champ |
| Champ de la classe | Champ |
| Constructeur | Constructeur |
|
| Méthode |
|
| Méthode |
| reste dans | (logique du jeu) |
Créer un fichier Menu.cs contenant la classe Menu instanciable.
Ajouter un nouveau fichier Menu.cs au projet avec le contenu suivant :
class Menu
{
// Champs (ex-variables globales)
string[] options;
int selectedIndex;
// Constructeur (ex-Menu_Init)
public Menu(string[] options)
{
this.options = options;
this.selectedIndex = 0;
}
// Méthode : afficher le menu (ex-Menu_ShowInteractive)
void ShowInteractive()
{
Console.Clear();
Console.WriteLine("Use arrows to navigate, Enter to select");
Console.WriteLine("");
for (int i = 0; i < this.options.Length; i++)
{
if (i == this.selectedIndex)
{
Console.BackgroundColor = ConsoleColor.White;
Console.ForegroundColor = ConsoleColor.Black;
Console.WriteLine($" > {this.options[i]} < ");
Console.ResetColor();
}
else
{
Console.WriteLine($" {this.options[i]} ");
}
}
Console.WriteLine("");
}
// Méthode : boucle interactive (ex-Menu_RunInteractive)
public int RunInteractive()
{
ConsoleKey key;
do
{
ShowInteractive();
ConsoleKeyInfo keyInfo = Console.ReadKey(true);
key = keyInfo.Key;
if (key == ConsoleKey.UpArrow)
{
this.selectedIndex--;
if (this.selectedIndex < 0)
{
this.selectedIndex = this.options.Length - 1;
}
}
else if (key == ConsoleKey.DownArrow)
{
this.selectedIndex++;
if (this.selectedIndex >= this.options.Length)
{
this.selectedIndex = 0;
}
}
} while (key != ConsoleKey.Enter);
return this.selectedIndex;
}
}
|
|
|
|
|
|
|
|
|
|
Modifier Program.cs pour utiliser la classe Menu au lieu des fonctions.
Remplacer le contenu de Program.cs par :
// Créer une instance de Menu
Menu mainMenu = new Menu(new string[] { "Play", "Options", "Highscores", "Quit" });
// Lancer le menu interactif
int choice = mainMenu.RunInteractive();
// Gérer le choix
Console.Clear();
switch (choice)
{
case 0:
Console.WriteLine("Starting game...");
break;
case 1:
Console.WriteLine("Opening options...");
break;
case 2:
Console.WriteLine("Showing highscores...");
break;
case 3:
Console.WriteLine("Goodbye!");
break;
}
Console.ReadKey();
Lancer l'application. Le comportement est identique à avant : navigation avec les flèches, sélection avec Enter.
|
|
|
|
Variables globales ( | Encapsulées dans l'objet |
Fonctions "en vrac" dans Program.cs | Méthodes dans |
Voici l'avantage décisif des instances. Créons un deuxième menu pour les options du jeu :
// Menu principal
Menu mainMenu = new Menu(new string[] { "Play", "Options", "Highscores", "Quit" });
int choice = mainMenu.RunInteractive();
if (choice == 1) // Options sélectionné
{
// Menu des options — un DEUXIÈME menu, indépendant !
Menu optionsMenu = new Menu(new string[] { "Sound", "Music", "Difficulty", "Back" });
int optionChoice = optionsMenu.RunInteractive();
Console.Clear();
switch (optionChoice)
{
case 0:
Console.WriteLine("Sound settings...");
break;
case 1:
Console.WriteLine("Music settings...");
break;
case 2:
Console.WriteLine("Difficulty settings...");
break;
case 3:
Console.WriteLine("Back to main menu...");
break;
}
}
else if (choice == 3) // Quit
{
Console.Clear();
Console.WriteLine("Goodbye!");
}
Console.ReadKey();
Menu_* ?Avec l'ancien code, options et selectedIndex étaient des variables globales. Lancer un deuxième menu aurait écrasé les données du premier.
Avec les instances :
mainMenu a ses propres options et selectedIndexoptionsMenu a ses propres options et selectedIndexAjoutez un champ title à la classe Menu et adaptez le constructeur :
class Menu
{
string[] options;
int selectedIndex;
string title;
public Menu(string title, string[] options)
{
this.title = title;
this.options = options;
this.selectedIndex = 0;
}
void ShowInteractive()
{
Console.Clear();
Console.WriteLine($"=== {this.title} ===");
Console.WriteLine("");
// ... reste du code
}
// ...
}
Utilisation :
Menu mainMenu = new Menu("SUPER GAME", new string[] { "Play", "Options", "Quit" });
Menu optionsMenu = new Menu("OPTIONS", new string[] { "Sound", "Music", "Back" });
Ajoutez des champs pour les couleurs de surbrillance :
class Menu
{
// ... champs existants ...
ConsoleColor highlightBg;
ConsoleColor highlightFg;
public Menu(string title, string[] options,
ConsoleColor highlightBg = ConsoleColor.White,
ConsoleColor highlightFg = ConsoleColor.Black)
{
this.title = title;
this.options = options;
this.selectedIndex = 0;
this.highlightBg = highlightBg;
this.highlightFg = highlightFg;
}
// Utiliser this.highlightBg et this.highlightFg dans ShowInteractive
}
Utilisation :
Menu mainMenu = new Menu("SUPER GAME", options, ConsoleColor.Cyan, ConsoleColor.Black);
Menu optionsMenu = new Menu("OPTIONS", optOptions, ConsoleColor.Yellow, ConsoleColor.Black);
Chaque menu a ses propres couleurs !
Variables globales | Champs de la classe |
Fonctions | Constructeur + méthodes |
Préfixe | Classe |
Un seul menu possible | Autant de menus que voulu |
Données accessibles partout | Données encapsulées dans l'objet |
class (sans static) = modèle pour créer des objetsnew = créer une instance avec ses propres donnéesthis = désigne l'instance courantePour l'instant, les champs de Menu sont accessibles depuis l'extérieur. La prochaine étape introduira les mots-clés private et public pour protéger les données de la classe.